package cn.huermao.hio.buffer;

import java.nio.ByteBuffer;
import java.util.concurrent.Semaphore;

/**
 * 虚拟ByteBuffer缓冲区
 * 虚拟内存的思想：
 * <p>
 * 1：先设置物理ByteBuffer的position和limit
 * 2：通过ByteBuffer.slice()生成虚拟ByteBuffer
 * 3：虚拟ByteBuffer与物理ByteBuffer共享字节数据，但是虚拟ByteBuffer
 * 有独立的position，limit，mark和capacity
 * </p>
 */
public final class VirtualBuffer {

    /**
     * 当前虚拟buffer的归属内存页
     */
    private final BufferPage bufferPage;

    /**
     * 通过ByteBuffer.slice()映射出来的虚拟ByteBuffer
     *
     * @see ByteBuffer#slice()
     */
    private ByteBuffer buffer;

    /**
     * 是否已回收
     */
    private Semaphore clean = new Semaphore(1);

    /**
     * 当前虚拟buffer映射的实际buffer.position
     */
    private int parentPosition;

    /**
     * 当前虚拟buffer映射的实际buffer.limit
     */
    private int parentLimit;

    /**
     * 虚拟缓冲区容量
     */
    private int capacity;

    /**
     * 构建新的虚拟ByteBuffer
     *
     * @param bufferPage     当前所属内存页
     * @param buffer         映射出来的buffer
     * @param parentPosition 实际物理position
     * @param parentLimit    实际物理limit
     */
    VirtualBuffer(BufferPage bufferPage, ByteBuffer buffer, int parentPosition, int parentLimit) {
        this.bufferPage = bufferPage;
        this.buffer = buffer;
        this.parentPosition = parentPosition;
        this.parentLimit = parentLimit;
        updateCapacity();
    }

    /**
     * 物理buffer封装为虚拟buffer
     *
     * @param buffer buffer
     * @return 封装的虚拟Buffer
     */
    public static VirtualBuffer wrap(ByteBuffer buffer) {
        return new VirtualBuffer(null, buffer, 0, 0);
    }

    int getParentPosition() {
        return parentPosition;
    }

    void setParentPosition(int parentPosition) {
        this.parentPosition = parentPosition;
        updateCapacity();
    }

    int getParentLimit() {
        return parentLimit;
    }

    void setParentLimit(int parentLimit) {
        this.parentLimit = parentLimit;
        updateCapacity();
    }

    private void updateCapacity() {
        capacity = this.parentLimit - this.parentPosition;
    }

    int getCapacity() {
        return capacity;
    }

    /**
     * 获取真实缓冲区
     *
     * @return 真实缓冲区
     */
    public ByteBuffer buffer() {
        return buffer;
    }

    /**
     * 设置真实缓冲区
     *
     * @param buffer 真实缓冲区
     */
    void buffer(ByteBuffer buffer) {
        this.buffer = buffer;
        clean.release();
    }

    /**
     * 释放虚拟缓冲区
     * 实际上为将此虚拟buffer加入回收队列
     */
    public void clean() {
        if (clean.tryAcquire()) {
            if (bufferPage != null) {
                bufferPage.recycle(this);
            }
        } else {
            throw new UnsupportedOperationException("虚拟内存已清理");
        }
    }

    @Override
    public String toString() {
        return "VirtualBuffer{parentPosition=" + parentPosition + ", parentLimit=" + parentLimit + '}';
    }
}